<!DOCTYPE html>
<script src="../../../resources/testharness.js"></script>
<script src="../../../resources/testharnessreport.js"></script>
<style>
    #first_child:first-child,
    #first_child:first-child #first_child_inner,
    #last_child:last-child,
    #last_child:last-child #last_child_inner,
    #only_child:only-child,
    #only_child:only-child #only_child_inner {
        background-color: green
    }

    span:first-child {
        color: green;
    }
</style>
<div>
    <div id="first_child">
        <div></div>
        <div></div>
        <div id="first_child_inner"></div>
        <div></div>
    </div>
</div>
<div>
    <div id="last_child">
        <div></div>
        <div></div>
        <div id="last_child_inner"></div>
        <div></div>
    </div>
</div>
<div>
    <div id="only_child">
        <div></div>
        <div></div>
        <div id="only_child_inner"></div>
        <div></div>
    </div>
</div>

<div>
    <span></span>
    XXX
    <span id="after_text_node"></span>
</div>

<script>
    function backgroundIsGreen(element) {
        assert_equals(getComputedStyle(element).backgroundColor, "rgb(0, 128, 0)");
    }

    function backgroundIsTransparent(element) {
        assert_equals(getComputedStyle(element).backgroundColor, "rgba(0, 0, 0, 0)");
    }

    test(() => {
        backgroundIsGreen(first_child);
        backgroundIsGreen(first_child_inner);
        backgroundIsGreen(last_child);
        backgroundIsGreen(last_child_inner);
        backgroundIsGreen(only_child);
        backgroundIsGreen(only_child_inner);
    }, "Check initial computed styles");

    var div = document.createElement("div");

    test(() => {
        first_child.offsetTop;
        first_child.parentNode.insertBefore(div, first_child);
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 3);
        backgroundIsTransparent(first_child);
        backgroundIsTransparent(first_child_inner);
    }, "Insert element before first child.");

    test(() => {
        first_child.offsetTop;
        div.remove();
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 2);
        backgroundIsGreen(first_child);
        backgroundIsGreen(first_child_inner);
    }, "Remove first child.");

    test(() => {
        last_child.offsetTop;
        last_child.parentNode.insertBefore(div, null);
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 3);
        backgroundIsTransparent(last_child);
        backgroundIsTransparent(last_child_inner);
    }, "Insert element before after last child.");

    test(() => {
        last_child.offsetTop;
        div.remove();
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 2);
        backgroundIsGreen(last_child);
        backgroundIsGreen(last_child_inner);
    }, "Remove last child.");

    test(() => {
        only_child.offsetTop;
        only_child.parentNode.insertBefore(div, only_child);
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 3);
        backgroundIsTransparent(only_child);
        backgroundIsTransparent(only_child_inner);
    }, "Insert element before only child.");

    test(() => {
        only_child.offsetTop;
        div.remove();
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 2);
        backgroundIsGreen(only_child);
        backgroundIsGreen(only_child_inner);
    }, "Remove element before only child.");

    test(() => {
        only_child.offsetTop;
        only_child.parentNode.insertBefore(div, null);
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 3);
        backgroundIsTransparent(only_child);
        backgroundIsTransparent(only_child_inner);
    }, "Insert element after only child.");

    test(() => {
        only_child.offsetTop;
        div.remove();
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 2);
        backgroundIsGreen(only_child);
        backgroundIsGreen(only_child_inner);
    }, "Remove element after only child.");

    test(() => {
        first_child.offsetTop;
        first_child.parentNode.insertBefore(div, null);
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1);
        div.remove();
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 0);
    }, "No first-child mutation.");

    test(() => {
        last_child.offsetTop;
        last_child.parentNode.insertBefore(div, last_child);
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1);
        div.remove();
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 0);
    }, "No last-child mutation.");

    test(() => {
        document.body.offsetTop;
        after_text_node.parentNode.insertBefore(div, after_text_node);
        if (window.internals)
            assert_equals(internals.updateStyleAndReturnAffectedElementCount(), 1);
    }, "Inserting sibling before text-node should not update for :first-child if text-node has element predecessor.");

</script>
